package com.docking.heylo.service.impl;

import com.docking.heylo.ThreadContext;
import com.docking.heylo.dao.entity.Post;
import com.docking.heylo.dao.entity.UserBlacklist;
import com.docking.heylo.dao.mapper.PostLikeMapper;
import com.docking.heylo.dao.mapper.UserBlacklistMapper;
import com.docking.heylo.dao.pojo.UserPostLike;
import com.docking.heylo.enums.EGender;
import com.docking.heylo.enums.EShowModel;
import com.docking.heylo.enums.EUserBlack;
import com.docking.heylo.exception.GeneralException;
import com.docking.heylo.pojo.Aperture;
import com.docking.heylo.pojo.SimplePost;
import com.docking.heylo.pojo.SimpleUser;
import com.docking.heylo.service.ICacheService;
import com.docking.heylo.service.IUserService;
import com.docking.heylo.utils.HeyloMessageSource;
import com.docking.heylo.utils.LocationUtil;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;


@Service
public class CacheServiceImpl implements ICacheService {

    @Autowired
    private EhCacheCacheManager cacheCacheManager;

    @Autowired
    private HeyloMessageSource ms;

    @Autowired
    private IUserService userService;

    @Resource
    private PostLikeMapper postLikeMapper;

    @Resource
    private UserBlacklistMapper userBlacklistMapper;



    private Logger logger = LoggerFactory.getLogger(CacheServiceImpl.class);

    @Override
    public void put(String key, Object value, long ttl) {

    }

    @Override
    public Map<String, Object> get(String key) {

        return null;
    }

    @Override
    public void sendSmsVerCode(String ip, String phone, String verCode) {
        Ehcache ehcache = cacheCacheManager.getCacheManager().getEhcache("enrollmentVerCode");
        Element element = ehcache.get(phone);
        if(element == null){
            Element saveElement = new Element(phone, verCode);
            ehcache.put(saveElement);
            logger.info("发送短信验证码{} ： {}", phone, saveElement.getObjectValue().toString());
        }else{
            long createTime = element.getCreationTime();
            long liveTime   = element.getTimeToLive();
            if(createTime + liveTime >= System.currentTimeMillis()){
                throw new GeneralException(ms.getMessage("send.sms.report"));
            }
        }
    }


    @Override
    public String getSmsVerCode(String phone) {
        Ehcache ehcache = cacheCacheManager.getCacheManager().getEhcache("enrollmentVerCode");
        Element element = ehcache.get(phone);
        return element == null ? null : element.getObjectValue().toString();
    }


    @Override
    public void pushPost(Post post, Integer type) {
        Ehcache ehcache = null;
        switch (type.intValue()){
            case 1:
                ehcache = photographerWorks();
                break;
            case 2:
                ehcache = modelWorks();
                break;
            case 3:
                ehcache = bigACache();
                break;
        }

        SimplePost simplePost = new SimplePost();
        simplePost.setPostId(post.getId());
        simplePost.setCoverPic(post.getCoverPic());
        simplePost.setContent(post.getContent());
        simplePost.setPicture(post.getPicture());
        simplePost.setLon(post.getLon());
        simplePost.setLat(post.getLat());
        simplePost.setLike(post.getLike());
        simplePost.setComments(post.getComments());
        simplePost.setUserId(post.getUserId());

        Element element = new Element(post.getUserId(), simplePost);
        ehcache.put(element);
        ehcache.flush();
    }










    /***
     * 每次在缓存中随机获取出10张最新作品
     *
     * @return
     */
    @Override
    public List<Aperture> apertureIndex() {
        List<Aperture> apertures;
        switch (ThreadContext.apertureMode()){
            case 1:                 // 认识身边的模特
                apertures = aperture_model(10);
                break;
            case 2:                 // 呼叫专属摄影师
                apertures =  aperture_photographer(10);
                break;
            case 3:                 // 社交模式
            default:
                apertures =  aperture_social();
                break;
        }

        // 判断是否插入大V
        Aperture bigA = bigA();
        if(bigA != null){
            apertures.add(bigA);
        }

        // 除去重复
        Set<Aperture> sets = new HashSet<>(apertures);
        List<Integer> userIds = new ArrayList<>();
        List<Integer> postIds = new ArrayList<>();
        for(Aperture aperture : sets){
            postIds.add(aperture.getPostInfo().getPostId());
            userIds.add(aperture.getUserInfo().getUserId());
        }

        // 喜欢
        List<UserPostLike> likes = postLikeMapper.countByUserIdAndPostId(ThreadContext.userId(), postIds);
        Map<String, UserPostLike> likeMap = new HashMap<String, UserPostLike>(){{
            for (UserPostLike like : likes){
                put(like.getPostId() + "", like);
            }
        }};
        
        // 拉黑
        List<UserBlacklist> blacklists = userBlacklistMapper.selectByUserIdAndPostId(ThreadContext.userId(), userIds, EUserBlack.yong_hu.getValue());
        Map<String, UserBlacklist> blackMap = new HashMap<String, UserBlacklist>(){{
            for (UserBlacklist black : blacklists){
                put(black.getTagId() + "", black);
            }
        }};

        Iterator<Aperture> iterator = sets.iterator();
        while (iterator.hasNext()){
            Aperture aperture = iterator.next();

            // 设置喜欢
            aperture.setLike(likeMap.get(aperture.getPostInfo().getPostId() + "") == null ? 0 : 1);

            // 计算距离
            try{
                BigDecimal distance = new BigDecimal(LocationUtil.getDistance(
                        aperture.getPostInfo().getLat().doubleValue(),
                        aperture.getPostInfo().getLon().doubleValue(),
                        ThreadContext.authorize.get().getLat().doubleValue(),
                        ThreadContext.authorize.get().getLon().doubleValue()
                )).setScale(0, BigDecimal.ROUND_DOWN);
                aperture.setDistance(distance.doubleValue());
                if(aperture.getDistance() == 0){
                    aperture.setDistance(1);
                }
            }catch (Exception e){
                System.out.println(String.format("计算距离出错：%s,%s,%s", ThreadContext.authorize.get().getLon(), ThreadContext.authorize.get().getLat(),e.getMessage()));
                aperture.setDistance(1);
            }

            if(blackMap.get(aperture.getUserInfo().getUserId() + "") != null){
                iterator.remove();
            }
        }

        // 打乱列表顺序
        List<Aperture> lists = new ArrayList<>(sets);
        Collections.shuffle(lists);
        return lists;
    }

    /***
     * 模特
     * @param number
     * @return
     */
    public List<Aperture> aperture_model(int number){
        return apertures(modelWorks(), number);
    }

    /***
     * 摄影师
     *
     * @param number
     * @return
     */
    public List<Aperture> aperture_photographer(int number){
        return apertures(photographerWorks(), number);
    }

    /***
     * 获取一个大A的作品
     *
     * @return
     */
    public Aperture bigA(){
        List<Aperture> apertures = apertures(bigACache(), 1);
        return apertures.isEmpty() ? null : apertures.get(0);
    }

    /***
     * 社交模式
     *
     * @return
     */
    public List<Aperture> aperture_social(){
        int number   = new Random().nextInt(10);

        List<Aperture> model = aperture_model(number);
        model.addAll(aperture_photographer(10 - number));

        return model;
    }

    public List<Aperture> apertures(Ehcache ehcache, int number){
        Ehcache userCache   = userInfoCache();

        List<Aperture> apertures = new ArrayList<>(number);
        List keys                = ehcache.getKeys();
        if(keys.size() > 0){
            Random          random   = new Random();
            for(int i = 0; i < number; i++){
                SimplePost  post    = (SimplePost) ehcache.get(keys.get(random.nextInt(keys.size()))).getObjectValue();
                Element     element = userCache.get(post.getUserId());

                Aperture aperture = new Aperture();
                aperture.setUserInfo(element == null || element.getObjectValue() == null ? userService.userForId(post.getUserId()) : (SimpleUser) element.getObjectValue());
                aperture.setPostInfo(post);

                // 筛选男女
                if(ThreadContext.showModel() == EShowModel.unlimited.getValue()){
                    apertures.add(aperture);
                }else if(ThreadContext.showModel() == EShowModel.female.getValue() && aperture.getUserInfo().getSex() == EGender.female.getValue()){
                    apertures.add(aperture);
                }else if(ThreadContext.showModel() == EShowModel.male.getValue() && aperture.getUserInfo().getSex() == EGender.male.getValue()){
                    apertures.add(aperture);
                }
            }
        }
        return apertures;
    }


    @Override
    public void removeCache(String cacheName, Object key) {
        Ehcache cache   = cacheCacheManager.getCacheManager().getEhcache(cacheName);
        boolean bool = cache.remove(key);
    }

    @Override
    public void postLike(Integer userId, boolean like) {
        Map<String, Object> map = findCacheAndPost(userId);
        Ehcache ehcache = (Ehcache) map.get("ehcache");
        Element element = (Element) map.get("element");


//        System.out.println(String.format("点赞作品用户ID：%s，实体：%s，当前点赞信息：%s", userId, element != null, element != null ? ((SimplePost) element.getObjectValue()).getLike() : " - "));

        // 没有找到作品
        if(element == null){ return; }

        SimplePost post = (SimplePost) element.getObjectValue();
        post.setLike(like ? post.getLike() + 1 : post.getLike() -1);

        // 保证不出现负数
        if(post.getLike() < 0){
            post.setLike(0);
        }

        ehcache.put(element);
        ehcache.flush();
    }

    @Override
    public void postComment(Integer userId) {
        Map<String, Object> map = findCacheAndPost(userId);
        Ehcache ehcache = (Ehcache) map.get("ehcache");
        Element element = (Element) map.get("element");

        if(element == null){ return; }

        SimplePost post = (SimplePost) element.getObjectValue();
        post.setComments(post.getComments() + 1);

        ehcache.put(element);
        ehcache.flush();
    }


    @Override
    public void post_remove(Map<String, Object> param) {
        Integer userId = (Integer) param.get("userId");

        Map<String, Object> map = findCacheAndPost(userId);
        Ehcache ehcache = (Ehcache) map.get("ehcache");
        Element element = (Element) map.get("element");

        if(element != null){
            ehcache.remove(userId);
            System.out.println(String.format("删除缓存：%s", ehcache.remove(userId)));
            ehcache.flush();
        }
    }


    public Map<String, Object> findCacheAndPost(Integer userId){
        Element element = null;
        Ehcache ehcache = null;
        Map<String, Object> result = new HashMap<>(2);
        result.put("element", element);
        result.put("ehcache", ehcache);

        ehcache = photographerWorks();

        // 检查是否摄影师作品
        if(ehcache.get(userId) != null){
            result.put("ehcache", ehcache);
            result.put("element", ehcache.get(userId));
            return result;
        }

        // 检查是否是模特
        ehcache = modelWorks();
        if(ehcache.get(userId) != null){
            result.put("ehcache", ehcache);
            result.put("element", ehcache.get(userId));
            return result;
        }

        // 检查是否是大A
        ehcache = bigACache();
        if(ehcache.get(userId) != null){
            result.put("ehcache", ehcache);
            result.put("element", ehcache.get(userId));
            return result;
        }

        return result;
    }




    public Ehcache photographerWorks(){
        return cacheCacheManager.getCacheManager().getEhcache("photographerWorks");
    }
    public Ehcache modelWorks(){
        return cacheCacheManager.getCacheManager().getEhcache("modelWorks");
    }
    public Ehcache bigACache(){
        return cacheCacheManager.getCacheManager().getEhcache("bigA");
    }
    public Ehcache userInfoCache(){
        return cacheCacheManager.getCacheManager().getEhcache("userInfoCache");
    }


    @Override
    public Aperture getAperture(Integer userId) {
        return null;
    }



}
